package com.nginx.web.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nginx.web.domain.PageQo;
import com.nginx.web.entity.*;
import com.nginx.web.mapper.ConfInfoMapper;
import com.nginx.web.service.ConfInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nginx.web.util.ApiUtil;
import com.nginx.web.util.Constants;
import com.nginx.web.util.ResultEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lyc
 * @since 2025-01-15
 */
@Service
public class ConfInfoServiceImpl extends ServiceImpl<ConfInfoMapper, ConfInfo> implements ConfInfoService {
    @Autowired
    private ConfigServiceImpl configService;
    @Autowired
    private HttpInfoServiceImpl httpInfoService;
    @Autowired
    private ServerInfoServiceImpl serverInfoService;
    @Autowired
    private LocationInfoServiceImpl locationInfoService;
    @Autowired
    private UpstreamInfoServiceImpl upstreamInfoService;
    @Autowired
    private UpstreamServerServiceImpl upstreamServerService;

    private static final String allCharReg = "[\\'\\\\、\\,\\u4E00-\\u9FA5\\~ \\^\\/\\*\\!\\$\"\\(\\)\\w\\s\\t\\n\\r.;#:=-]+";
    private static final String allCharRegZero =  StrUtil.removeSuffix(allCharReg , "+") + "*";
    // 读取nginx配置
    public void readConfInfo() {
        remove(null);
        httpInfoService.remove(null);
        serverInfoService.remove(null);
        locationInfoService.remove(null);
        upstreamInfoService.remove(null);
        upstreamServerService.remove(null);

        Config config = configService.getOne(Wrappers.lambdaQuery(Config.class)
                .eq(Config::getKey, Constants.nginx_path));
        File dir = new File(config.getValue());
        this.checkFile(dir , dir);
    }
    // 遍历读取nginx文件
    public void checkFile(File topDir, File dir){
        if(dir.isDirectory()){
            File[] files = dir.listFiles();
            for (File file : files) {
                checkFile(topDir , file);
            }
        }
        if(StrUtil.equals(dir.getName() , "fastcgi.conf")){
            return;
        }
        if(dir.isFile() && StrUtil.equals(FileUtil.getSuffix(dir) , "conf")){
            String absolutePath = dir.getAbsolutePath().replace( topDir.getAbsolutePath() , "");
            ConfInfo confInfo = new ConfInfo();
            confInfo.setName(dir.getName());
            confInfo.setPath(absolutePath);

            String content = FileUtil.readUtf8String(dir);

            String serverReg = "\\#*\\s*server\\s*\\{" + allCharReg + "(\\{" + allCharReg + "\\}" + allCharRegZero + ")+\\W\\}";

            String httpText = ReUtil.getGroup0("http\\s*\\{[\\w\\W]*\\}", content);
            List<String> serverList = ReUtil.findAllGroup0(serverReg, content);

            if(StrUtil.isNotEmpty(httpText)){

                String confExtendText = StrUtil.removeAll(content, httpText);
                confInfo.setText(removeEmptyLine(confExtendText));
                this.save(confInfo);
                String httpContent = ReUtil.delLast("\\}" , ReUtil.delFirst("http\\s*\\{",httpText )) ;
                String noServer = ReUtil.delAll(serverReg, httpContent);
                String upstreamRegex = "upstream[\\s\\t]+\\w+[\\s\\t]*\\{[\\w\\s\\t\\n\\r.;#:=]+\\}";
                String noStream = ReUtil.delAll(upstreamRegex,noServer);

                String httpExtend = removeEmptyLine(noStream );
                HttpInfo httpInfo = new HttpInfo();
                httpInfo.setText(httpExtend);
                httpInfo.setConfInfoId(confInfo.getId());
                httpInfoService.save(httpInfo);
                List<String> upstreamList = ReUtil.findAllGroup0(upstreamRegex, httpContent);
                for (String steamStr : upstreamList) {
                    UpstreamInfo upstreamInfo = new UpstreamInfo();
                    String group0 = ReUtil.getGroup0("upstream.+\\{", steamStr);
                    String name = ReUtil.delAll("upstream|\\{|\\t|\\s", group0);
                    upstreamInfo.setName(name);
                    upstreamInfo.setConfInfoId(confInfo.getId());
                    upstreamInfo.setConfInfoName(confInfo.getName());
                    upstreamInfo.setHttpInfoId(httpInfo.getId());
                    upstreamInfoService.save(upstreamInfo);
                    List<String> streamServerList = ReUtil.findAllGroup0("\\#*[\\s]*server[\\s]+[\\d\\s\\w.:=]+\\s*;", steamStr);

                    for (String streamServer : streamServerList) {
                        boolean isEnable = !StrUtil.startWith(streamServer, "#");
                        String address = ReUtil.getGroup0("[\\d.:]+", streamServer);
                        String streamServerExtend = ReUtil.delAll("server|#server|;|"+address, streamServer);
                        String trim = StrUtil.trim(streamServerExtend);

                        UpstreamServer upstreamServer = new UpstreamServer();
                        upstreamServer.setAddress(address);
                        upstreamServer.setIsEnable(isEnable?1:0);
                        upstreamServer.setText(trim);
                        upstreamServer.setUpstreamInfoId(upstreamInfo.getId());
                        upstreamServer.setUpstreamInfoName(upstreamInfo.getName());
                        upstreamServerService.save(upstreamServer);
                    }
                }
                readServer(serverList , confInfo.getId(), httpInfo.getId() , confInfo.getName());
            }else{
                this.save(confInfo);
                readServer(serverList ,  confInfo.getId() , null , confInfo.getName());
            }
        }
    }
    // 读取server信息
    private void readServer(List<String> serverList ,Integer confId , Integer httpId , String confName){
        for (String serverStr : serverList) {
            String listen = ReUtil.getGroup0("listen[\\w\\s]+;", serverStr);
            String port = ReUtil.getGroup0("\\d+", listen);
            String serverName = ReUtil.getGroup0("server_name[\\w\\s\\.]+;", serverStr);
            String sn = ReUtil.delAll("server_name|;|\\s", serverName);
            ServerInfo serverInfo = new ServerInfo();
            serverInfo.setListen(Integer.parseInt(port));
            serverInfo.setServerName(sn);
            boolean serverEnable = !ReUtil.isMatch("\\#+\\s*server[\\W\\w]+", serverStr);
            serverInfo.setIsEnable(serverEnable?1:0);
            serverInfo.setHttpInfoId(httpId);
            serverInfo.setConfInfoId(confId);
            serverInfo.setConfInfoName(confName);
            String text = ReUtil.delAll("\\#*\\s*location" + allCharReg + "\\{" + allCharReg + "\\}"
                    + "|listen[\\w\\s]+;" + "|server_name[\\w\\s\\.]+;" , serverStr);
            text = ReUtil.delLast("\\}" , ReUtil.delFirst("server\\s*\\{",text )) ;
            text = removeEmptyLine(text);
            serverInfo.setText(text);
            serverInfoService.save(serverInfo);
            List<String> locationList = ReUtil.findAllGroup0("\\#*\\s*location" + allCharReg + "\\{"+allCharReg+"\\}", serverStr);
            for (String location : locationList) {
                LocationInfo locationInfo = new LocationInfo();
                boolean isEnable = !ReUtil.isMatch("\\#+\\s*location[\\W\\w]+", location);

                String urlTxt = ReUtil.getGroup0("location" + allCharReg + "\\{", location);
                urlTxt = ReUtil.delAll("location|\\{|\\s" , urlTxt);
                String locationText = ReUtil.getGroup0("\\{" + allCharReg + "\\}", location);
                locationText = StrUtil.trim(ReUtil.delAll("\\{|\\}" , locationText));
                locationText = StrUtil.removeSuffix(locationText,"#");
                locationInfo.setUrl(urlTxt);
                locationInfo.setIsEnable(isEnable?1:0);
                locationInfo.setListen(serverInfo.getListen());
                locationInfo.setServerInfoId(serverInfo.getId());
                locationInfo.setText(locationText);
                locationInfoService.save(locationInfo);
            }
        }
    }
    // 写入nginx配置
    public void writeConfInfo() {
        List<ConfInfo> list = list();
        for (ConfInfo confInfo : list) {
            List<HttpInfo> httpInfoList = httpInfoService.list(Wrappers.lambdaQuery(HttpInfo.class)
                    .eq(HttpInfo::getConfInfoId, confInfo.getId()));
            confInfo.setHttpInfoList(httpInfoList);
            List<ServerInfo> serverInfoList = serverInfoService.list(Wrappers.lambdaQuery(ServerInfo.class)
                    .eq(ServerInfo::getConfInfoId, confInfo.getId()));
            confInfo.setServerInfoList(serverInfoList);
            this.consServerInfo(serverInfoList);
            for (HttpInfo httpInfo : httpInfoList) {
                List<ServerInfo> serverList = serverInfoService.list(Wrappers.lambdaQuery(ServerInfo.class)
                        .eq(ServerInfo::getHttpInfoId, httpInfo.getId()));
                httpInfo.setServerInfoList(serverList);
                this.consServerInfo(serverList);

                List<UpstreamInfo> upstreamInfoList = upstreamInfoService.list(Wrappers.lambdaQuery(UpstreamInfo.class)
                        .eq(UpstreamInfo::getHttpInfoId, httpInfo.getId()));
                httpInfo.setUpstreamInfoList(upstreamInfoList);

                for (UpstreamInfo upstreamInfo : upstreamInfoList) {
                    List<UpstreamServer> upstreamServerList = upstreamServerService.list(Wrappers.lambdaQuery(UpstreamServer.class)
                            .eq(UpstreamServer::getUpstreamInfoId, upstreamInfo.getId()));
                    upstreamInfo.setUpstreamServerList(upstreamServerList);
                }

            }
        }
        Config config = configService.getOne(Wrappers.lambdaQuery(Config.class)
                .eq(Config::getKey, Constants.nginx_path));
        String path = config.getValue();
        for (ConfInfo confInfo : list) {
            File file = new File(path + confInfo.getPath());
            FileUtil.mkParentDirs(file);
            try {
                if(file.exists()){
                    FileUtil.del(file);
                }
                file.createNewFile();
            }catch (Exception e){
                e.printStackTrace();
                ApiUtil.back(ResultEnum.ERROR , "文件创建失败");
            }
            StringBuilder sr = new StringBuilder();
            if(StrUtil.isNotEmpty(confInfo.getText())){
                sr.append(confInfo.getText());
            }
            List<HttpInfo> httpInfoList = confInfo.getHttpInfoList();
            if(CollUtil.isNotEmpty(httpInfoList)){
                for (HttpInfo httpInfo : httpInfoList) {
                    String text = httpInfo.getText();
                    sr.append("http {") ;
                    sr.append(StrUtil.isNotEmpty(text) ? text : "'");

                    List<UpstreamInfo> upstreamInfoList = httpInfo.getUpstreamInfoList();
                    if(CollUtil.isNotEmpty(upstreamInfoList)){
                        for (UpstreamInfo upstreamInfo : upstreamInfoList) {
                            sr.append("\tupstream " +upstreamInfo.getName() + "{" ) ;
                            for (UpstreamServer upstreamServer : upstreamInfo.getUpstreamServerList()) {
                                String isEnable = upstreamServer.getIsEnable() == 1 ? "" : "#";
                                sr.append("\n\t\t" + isEnable +"server " +upstreamServer.getAddress() + " " + upstreamServer.getText() + ";" );
                            }
                            sr.append("\n\t}\n");
                        }
                        sr.append("\n");
                    }
                    List<ServerInfo> serverInfoList = httpInfo.getServerInfoList();
                    if(CollUtil.isNotEmpty(serverInfoList)){
                        getServerWrite(serverInfoList , sr , "\t");
                    }
                    sr.append("\n}") ;
                }
            }else{
                List<ServerInfo> serverInfoList = confInfo.getServerInfoList();
                getServerWrite(serverInfoList ,sr , "");
            }
            FileUtil.writeUtf8String(sr.toString() , file);
        }
        System.out.println(list);
    }
    // 写入server配置
    public void getServerWrite(List<ServerInfo> serverInfoList , StringBuilder sr , String tab){
        for (ServerInfo serverInfo : serverInfoList) {
            String pre = serverInfo.getIsEnable() == 1? "" : "#";
            sr.append(tab + pre + "server {\n");
            sr.append(tab + pre +"\tlisten " + serverInfo.getListen() + ";\n");
            sr.append(tab + pre +"\tserver_name " + serverInfo.getServerName() + ";");
            sr.append(serverInfo.getText() + "\n");
            for (LocationInfo locationInfo : serverInfo.getLocationInfoList()) {
                String loPre = locationInfo.getIsEnable() == 1? "" : "#";
                sr.append(tab + pre + loPre + "\tlocation " + locationInfo.getUrl() + "{\n");
                sr.append(tab  +"\t\t"+locationInfo.getText());
                sr.append("\n" + tab + pre + loPre + "\t}\n\n");
            }
            sr.append(tab + pre + "}\n");
        }
    }
    // 从数据构建server信息
    public void consServerInfo(List<ServerInfo> serverInfoList){
        for (ServerInfo serverInfo : serverInfoList) {
            List<LocationInfo> upstreamServerList = locationInfoService.list(Wrappers.lambdaQuery(LocationInfo.class)
                    .eq(LocationInfo::getServerInfoId, serverInfo.getId()));
            serverInfo.setLocationInfoList(upstreamServerList);
        }
    }
    // 去除空行
    public static String removeEmptyLine(String str){
        List<String> split = StrUtil.split(str, "\n");
        StringBuilder stringBuilder = new StringBuilder();
        for (String line : split) {
            if(StrUtil.isNotEmpty(StrUtil.trim(line))){
                if(StrUtil.equals(StrUtil.trim(line) , "#")){
                    continue;
                }
                stringBuilder.append("\n");
                stringBuilder.append(line);
            }
        }
        stringBuilder.append("\n");
        return stringBuilder.toString();
    }

    // 查询nginx配置
    public Page<ConfInfo> listConfInfo(PageQo pageQo) {
        Page<ConfInfo> page = new Page<>(pageQo.getPage() , pageQo.getLimit());
        LambdaQueryWrapper<ConfInfo> wrapper = Wrappers.lambdaQuery(ConfInfo.class).orderByAsc(ConfInfo::getSort);
        page(page , wrapper);
        List<ConfInfo> records = page.getRecords();
        List<Integer> idList = new ArrayList<>();
        Map<Integer , ConfInfo> map = new HashMap<>();
        for (ConfInfo record : records) {
            idList.add(record.getId());
            map.put(record.getId() , record);
        }
        List<HttpInfo> list = httpInfoService.list(Wrappers.lambdaQuery(HttpInfo.class)
                .in(HttpInfo::getConfInfoId, idList));
        for (HttpInfo httpInfo : list) {
            map.get(httpInfo.getConfInfoId()).setHasHttp(true);
        }

        return page;
    }
    // 修改nginx配置
    public void updateConfInfo(ConfInfo confInfo) {
        updateById(confInfo);
    }
}
